package com.xinyue.ext.reader.dao;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;

import com.xinyue.ext.data.FinderData;
import com.xinyue.ext.exception.FinderException;
import com.xinyue.ext.reader.ParamHolder;
import com.xinyue.ext.util.StringUtil;

public class HqlProcess extends DaoContext{
	//私有构造器
	private HqlProcess() {
	}
	//内部类
	private static class SingletonHolder{
        private static HqlProcess instance = new HqlProcess();  
    }
	/**
	 * 获得对象实例
	 */
	public static HqlProcess getInstance(ParamHolder holder) {
		DaoContext.holder = holder;
		return SingletonHolder.instance;
	}
	

	/**
	 * 读取hql标签数据
	 * param finder finder标签
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void read(Element finder) throws FinderException {
		List<Element> hqs = finder.elements(hql_);
		
		//存在hql标签
		if(hqs != null && hqs.size() > 0) {
			List<FinderData> finders = new ArrayList<FinderData>();
			
			for (Element e: hqs) {
				FinderData find = commonRead(e);
				//返回值、强制类型转换、是否单个结果集处理
				hqlReturn(e, find);
				//入参、paramSetter及hql语句处理
				hqlProcess(e, find);
				
				finders.add(find);
			}
			
			holder.getEntity().getDao().setHqls(finders);;
		}
	}
	
	private void hqlReturn(Element hql, FinderData find) throws FinderException {
		String type = hql.attributeValue(returnType_);
		if(StringUtil.isNull(type)) {
			throw new FinderException("hql标签未定义returnType属性或其值为空:" + type, holder.getException());
		}
		
		//query类型判断
		if(!find.isQuery() && !"Integer".equals(type)) {
			throw new FinderException("hql标签query属性为false时，返回值只能是Integer:" + type, holder.getException());
		}
		
		if(holder.getEntity().getClassName().equals(type)) {
			find.setConvert(true);
			find.setOnly(true);
			find.setReturnType(holder.getEntity().getClassName());
		}else if(LIST.equals(type)) {
			find.setWarning(true);
			find.setReturnType("List<" + holder.getEntity().getClassName() + ">");
		}else {
			returnType(type, find);
		}
	}

	
	/**
	 * 对SQL语句进行预处理
	 * @throws FinderException
	 */
	@SuppressWarnings("unchecked")
	private void hqlProcess(Element hql, FinderData find) throws FinderException {
		//入参处理
		String inType = hql.attributeValue(paramType_); 
		//定义入参
		List<Element> params = hql.elements(query_param_);
		
		//如果未定义paramType属性
		if(StringUtil.isNull(inType)) {
			if(params != null && params.size() > 0) {
				String param = "";
				List<String> setter = new ArrayList<String>();
				
				for (Element p: params) {
					String name = p.attributeValue(name_);
					if(StringUtil.isNull(name)) {
						throw new FinderException("query-param标签没有定义name属性或者其值为空", holder.getException());
					}
					
					String type = p.attributeValue(type_);
					if(StringUtil.isNull(type)) {
						throw new FinderException("query-param标签没有定义type属性或者其值为空", holder.getException());
					}
					//验证参数是否合法并返回setter
					String set = setterHQL(name, type);
					if(set == null) {
						throw new FinderException("query-param标签type属性值不合法:" + type, holder.getException());
					}
					setter.add(set);
					
					param += type + " " + name + ", ";
				}
				
				find.setParams(param.substring(0, param.length() - 2));
				find.setParamSetter(setter);
			}
		}else {
			if(!find.isQuery()) {
				throw new FinderException("hql标签定义paramType属性时,query标签必须为true", holder.getException());
			}
			
			if(MAP.equals(inType)) {
				if(params != null && params.size() > 0) {
					throw new FinderException("hql标签定义paramType属性时,query-param标签无效", holder.getException());
				}
				
				holder.getDaoImpt().add("java.util.Map");
				find.setParams("Map<String, Object> map");
			}else {
				throw new FinderException("hql标签的paramType属性值非法:" + inType, holder.getException());
			}
		}
		
		//hql语句
		Element state = hql.element(hql_state_);
		if(state == null) {
			throw new FinderException("hql标签的hql_state未定义", holder.getException());
		}
		
		processQL(state, find);
	}
}
